#pragma once
#ifndef __GLF_DEBUGGER_NETINTERFACE_H__
#define __GLF_DEBUGGER_NETINTERFACE_H__

#include <glf/config.h>

#if GLF_ENABLE_DEBUGGER

#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#	include <glf/wp8/socket.h>
#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#   include <Winsock2.h>
#   include <Ws2tcpip.h>
#elif defined(WIN32)
#   include <Winsock2.h>
#   include <Ws2tcpip.h>
#   define strdup _strdup
#elif defined(GLF_PLATFORM_XBOX)
#   include <xtl.h>
#   include <winsockx.h>
#   define strdup _strdup
#elif defined(GLF_PLATFORM_PS3)
#   include <sys/socket.h>
#   include <fcntl.h>
#   include <unistd.h>
#   include <errno.h>
#   include <arpa/inet.h>
#   include <netdb.h>
#   include <sys/timer.h>
#   include <sys/select.h>
#   include <netinet/in.h>
#   include <netex/net.h>
#   include <netex/libnetctl.h>
#   include <netex/errno.h>
#   include <cell/sysmodule.h>
    typedef int SOCKET;
#   define closesocket close
#   define SOCKET_ERROR -1
#   define WSAGetLastError() sys_net_errno
#   define WSAEWOULDBLOCK SYS_NET_EAGAIN
#   define INVALID_SOCKET -1
#   define WSAENOBUFS EAGAIN
#   define SOCKADDR_IN sockaddr_in
#   define LPSOCKADDR sockaddr*
#   define SOMAXCONN 5
#elif defined(GLF_PLATFORM_PSP2)
#   include <net.h>
#   include <libnetctl.h>
#	define fd_set SceNetFdSet
#	define FD_ZERO SCE_NET_FD_ZERO
#	define FD_SET SCE_NET_FD_SET
#	define FD_ISSET SCE_NET_FD_ISSET
	typedef int SOCKET;
	struct timeval {int m, s;};
#   define closesocket sceNetSocketClose
#	define bind sceNetBind
#	define listen sceNetListen
#	define accept sceNetAccept
#	define send sceNetSend
#	define sendto sceNetSendto
#	define recv sceNetRecv
#	define recvfrom sceNetRecvfrom
#	define htons sceNetHtons
#   define SOCKET_ERROR -1
#   define WSAGetLastError() sce_net_errno
#   define WSAEWOULDBLOCK SCE_NET_EWOULDBLOCK
#   define INVALID_SOCKET -1
#   define WSAENOBUFS SCE_NET_EAGAIN
#   define SOCKADDR_IN SceNetSockaddrIn
#   define LPSOCKADDR SceNetSockaddr*
#   define SOMAXCONN 5
#elif defined(GLF_PLATFORM_CTR)
#   include <nn/socket.h>
#   include <nn/ac.h>
#   include <nn/fs.h>
#   define closesocket		nn::socket::Close
#   define SOCKET_ERROR	-1
#   define INVALID_SOCKET	nn::socket::EBADF
#   define SOCKADDR_IN		nn::socket::SockAddrIn
#   define INADDR_ANY		NN_SOCKET_INADDR_ANY
#   define hostent			nn::socket::HostEnt
#   define SOMAXCONN 5
	typedef s32 SOCKET;
#else
#   include <sys/socket.h>
#   include <fcntl.h>
#   include <unistd.h>
#   include <errno.h>
#   include <arpa/inet.h>
#   include <netdb.h>
    typedef int SOCKET;
#   define closesocket close
#   define SOCKET_ERROR -1
#   define WSAGetLastError() errno
#   define WSAEWOULDBLOCK EAGAIN
#   define INVALID_SOCKET ENOTSOCK
#   define WSAENOBUFS EAGAIN
#   define SOCKADDR_IN sockaddr_in
#   define LPSOCKADDR sockaddr*
#endif

#include <string>

namespace glf
{
namespace debugger
{

bool CNetInterfaceInit();

class CNetSocket //: public CNetSocket
{
public:
	CNetSocket(SOCKET sock);
	virtual ~CNetSocket();

	virtual int getError() const;
	virtual bool isOpen() const;
	virtual bool isReadable() const;
	virtual int read(void* data, int bytes, float timeout_seconds);
	virtual int write(const void* data, int bytes, float timeout_seconds);
	void setNonBlock(bool nonBlock);

private:
	SOCKET Sock;
	mutable int Error;
};

class CNetInterface //: public net_interface
{
public:
	CNetInterface();
	~CNetInterface();

	void close();

	// server
	bool listen(int port);
	CNetSocket* accept();

	// multicast
	bool setupReceiveMulticast(const char* group, int port);
	int receiveMulticast(void* data, int size);
	bool sendDatagram(const char* address, int port, void* data, int size);

	bool getHostName(char* buffer, int len);
	bool getHostAddress(char* buffer, int len) const;
	void setNonBlock();
	bool isValid() const;
	int getPort() const { return mPortNumber; }

private:
	std::string mGroup;
	int mPortNumber;
	SOCKET mSocket;
};

} // namespace debugger
} // namespace glf

#endif

#endif
